#include "gui.browser.h"

// Constructor
TOB::UIBrowser::UIBrowser(uint16 x, uint16 y, uint16 w, uint16 h, Config &c):
  UIWindow(x, y, w, h), code(c) { 
  std::string tmp = "="; splitter = CONVERT(tmp);
  colors[code["color-red"]] = Color::Red;
  colors[code["color-green"]] = Color::Green;
  colors[code["color-blue"]] = Color::Blue;
  colors[code["color-magenta"]] = Color::Magenta;
  colors[code["color-cyan"]] = Color::Cyan;
  colors[code["color-yellow"]] = Color::Yellow;
  colors[code["color-white"]] = Color::White;
  links.push_back(std::string());
  linkStack.push_back(0);
}


// Destructor
TOB::UIBrowser::~UIBrowser() { }


// Set focus
void TOB::UIBrowser::focus() {
  running = true;
  showCursor(true);
  x = y = 0;
  uint32 lnk;

  while(running) {
    setCursor(x, y);
    Char ch = getChar();

    switch(ch) {
     // Down
     case KEY_DOWN:
      moveY(1);
      break;

     // Up
     case KEY_UP:
      moveY(-1);
      break;

     // Left
     case KEY_LEFT:
      moveX(-1);
      break;

     // Right
     case KEY_RIGHT:
      moveX(1);
      break;

     // Link
     case '\n':
      if(y >= pixelMap.size()) { break; }
      if(x >= pixelMap[y].size()) { break; }
      lnk = pixelMap[y][x].link;
      if(lnk) {
        try {
          eventLink(links[lnk]);
        } catch(std::bad_function_call) { }
      }
      break;

     case 27:
      running = false;
      break;
    }
  }
}


// Set new page
void TOB::UIBrowser::setPage(std::string &page) {
  scrollX = scrollY = 0;
  render(CONVERT(page));
  print();
}


void TOB::UIBrowser::moveX(int8 direction) {
  if(direction > 0 && x < width -1) {
    ++x;
  } else if(direction < 0 && x) {
    --x;
  }
}


void TOB::UIBrowser::moveY(int8 direction) {
  if(direction > 0) {
    if(static_cast<uint16>(y) < height - 1) {
      ++y;
    } else if(scrollY + height < pixelMap.size()) {
      ++scrollY;
      print();
    }
  } else if(direction < 0) {
    if(y) {
      --y;
    } else if(scrollY) {
      --scrollY;
      print();
    }
  }
}


void TOB::UIBrowser::render(String page) {
  // Prepare
  pixelMap.clear();
  pixelMap.push_back(std::vector<BPixel>());

  // Create iterators
  colorStack.clear();
  colorStack.push_back(Color::Default);
  x = y = 0;
  ignore = skip = false;
  
  // Symbol by chbol
  for(uint32 i = 0; i < page.size(); ++i) {
    std::vector<BPixel> &line = pixelMap[y];
    Char ch = page[i];

    switch(ch) {

     // Tag begining
     case '[':
      iter = i + 1;
      ignore = true;
      break;

     // Tag ending
     case ']':
      parseTag(String(page.begin() + iter, page.begin() + i));
      ignore = false;
      break;

     // Default
     default:
      if(!ignore && ch != '\n') {
        line.push_back({ch, 
          colorStack[colorStack.size()-1], 
          linkStack[linkStack.size()-1]
        });
        if(++x == width - 1) {
          ++y;
          pixelMap.push_back(std::vector<BPixel>());
          x = 0;
        }
      }
      break;
    }
  }
}


void TOB::UIBrowser::print() {
  uint16 y = 0;
  for(uint32 i = 0; i < height; ++i) {
    setCursor(0, i);
    clearLine();
  } 

  for(uint32 i = scrollY; i < scrollY + height; ++i) {
    if(i >= pixelMap.size()) { break; }
    setCursor(0, y++);
    for(uint32 j = scrollX; j < scrollX + width; ++j) {
      if(j >= pixelMap[i].size()) { break; }
      BPixel &pixel = pixelMap[i][j];
      setColor(pixel.color);
      if(pixel.link) { setColor(Color::Link); }
      putChar(pixel.ch);
    }
  }
}


void TOB::UIBrowser::parseTag(String tag) {
  uint32 sid = tag.find(splitter);
  String key = (sid != String::npos) 
    ? tag.substr(0, sid) : tag;
  String value = (sid != String::npos)
    ? tag.substr(sid + 1) : String();

  // Color
  if(key == code["tag-color"]) {
    colorStack.push_back(colors[value]);
  } else if(key == code["ctag-color"]) {
    if(colorStack.size() > 1) {
      colorStack.pop_back();
    }
  }

  // break
  else if(key == code["tag-break"]) {
    ++y;
    pixelMap.push_back(std::vector<BPixel>());
    x = 0;
  }

  // link
  else if(key == code["tag-link"]) {
    links.push_back(CONVERT(value));
    linkStack.push_back(links.size()-1);
  } else if(key == code["ctag-link"]) {
    if(linkStack.size() > 1) {
      linkStack.pop_back();
    }
  }
}
